package com.rois.librois.libRoISComp;

import java.util.Properties;
import java.util.Vector;
import java.util.logging.Logger;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;

import com.rois.librois.RoIS.Completed_Status;
import com.rois.librois.RoIS.ErrorType;
import com.rois.librois.RoIS.Result;
import com.rois.librois.RoIS.ResultListHolder;
import com.rois.librois.libRoISComp.ComponentEntity;
import com.rois.librois.libRoISComponentServer.ComponentInterfaceImpl;
import com.rois.librois.libRoISComponentServer.ServerImpl;
import com.rois.librois.libRoISComponentServer.ServerOperationImpl;
import com.rois.librois.libRoISMessageStorage.RoIS_Engines;

/**
 * Library class for RoIS Component.
 * This object controls CORBA server of RoIS Component and CORBA client of HRI Engine.
 * This object holds information of messages exchanged between Component and Engine(s).
 *
 * @author Miki Sato <miki.sato.1225@gmail.com>
 *
 *    The MIT licence
 *
 *    Copyright (C) 2011
 *      ATR Intelligent Robotics and Communication Laboratories, Japan
 *
 *    Permission is hereby granted, free of charge, to any person obtaining a copy
 *    of this software and associated documentation files (the "Software"), to deal
 *    in the Software without restriction, including without limitation the rights
 *    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 *    of the Software, and to permit persons to whom the Software is furnished to do so,
 *    subject to the following conditions:
 *
 *    The above copyright notice and this permission notice shall be included in all
 *    copies or substantial portions of the Software.
 *
 *    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 *    INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 *    PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 *    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 *    OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 *    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

public class libRoISComp {
	// component server operation class
	private ServerOperationImpl m_server_op_impl = new ServerOperationImpl();
	// component interface class
	private ComponentInterfaceImpl m_comp_impl = new ComponentInterfaceImpl(this);
	// component name service
	private String m_component_nameservice;
	// component server name
	private String m_component_servername;
	// initialize flag
	// engine name service
	private String m_engine_nameservice;
	// engine server name
	private String m_engine_servername;
	// initialize state
	private boolean m_server_init = false;
	private boolean m_client_init = false;;
	private boolean m_engine_init = false;
	// maximum bind number
	int m_component_bindmax = 1;		//@@ FOR DUMMY: default bindable number is 1
	// current directory path
	private String m_current_directory;
	// rois profile name
	private String m_profile_filename;
	// message buffer
	private RoIS_Engines m_Engines = new RoIS_Engines();

////////////////////////////////////////////////////////////////////////////////////////////////////
// For Initialize / Finalize
////////////////////////////////////////////////////////////////////////////////////////////////////
	/**
	 * initialize Component server and Engine client.
	 * Component server is defined in RoIS_COMPONENT_PARAM.properties (servename:COMPONENT_IF, namingservice:CMP_NAME_HOST).
	 * Engine server is defined in RoIS_COMPONENT_PARAM.properties (servename:ENGINE_IF, namingservice:ENG_NAME_HOST).
	 * @param comp_ent_val ComponentEntity object. Implementation of ComponentEntity should be created in each component.
	 * @return true/false
	 */
	public boolean initialize(
		ComponentEntity comp_ent_val
	)
	{
		boolean bRes = false;

		//-----------------------------------------------
		// initialize Component Server
		//-----------------------------------------------
		// read properties
		final Properties prop = new Properties();
		InputStream in_stream = null;
		try {
			in_stream = new FileInputStream(
				new File("RoIS_COMPONENT_PARAM.properties")
			);
			prop.load(in_stream);
		} catch (IOException e) {
			Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info("failed to open properties.");
			return bRes;
		}
		m_component_nameservice = prop.getProperty("CMP_NAME_HOST");
		m_component_servername = prop.getProperty("COMPONENT_IF");
		int iRetry = Integer.parseInt(prop.getProperty("RETRY_NUM"));
		m_profile_filename = m_component_servername + ".xml";
		// initialize server
		int counterServerRetry  = 0;
		while(!bRes && counterServerRetry<iRetry)
		{
			// configure name service
			bRes = m_server_op_impl.initialize(m_component_nameservice);
			if(bRes)
			{
				// create server implementation class
				ServerImpl server_impl = new ServerImpl();
				// set component entity object to component implementation object
				m_comp_impl.setComponentEntity(comp_ent_val);
				// set component implementation object to server implementation object
				server_impl.setComp(m_comp_impl);
				// set server implementation object to server operation object
				m_server_op_impl.setServerImpl(server_impl);
				// register server
				bRes = m_server_op_impl.register(m_component_servername);
				if(bRes)
				{
					// start the server
					bRes = m_server_op_impl.start();
				}
			}
			counterServerRetry++;
		}
		if(!bRes)
		{
			Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info("cannot start server.");
			return bRes;
		}
		m_server_init = true;
		Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info("server has started.");

		//-----------------------------------------------
		// initialize Engine Client
		//-----------------------------------------------
		// read properties
		m_engine_nameservice = prop.getProperty("ENG_NAME_HOST");
		m_engine_servername = prop.getProperty("ENGINE_IF");
		// check connection
		if(m_Engines.size!=0)
		{
			for(int i=0; i<m_Engines.size; i++)
			{
				if(m_Engines.servername.get(i).matches(m_engine_servername))
				{
					Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info("already connected to: " + m_engine_servername);
					bRes = true;
					return bRes;
				}
			}
		}
		bRes = m_Engines.client_p.start(m_engine_nameservice, m_engine_servername);
		// start the client
		if(!bRes)
		{
			Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info("cannot start client.");
			return bRes;
		}
		else
		{
			m_Engines.push_back(
				true,
				0,
				m_engine_nameservice,
				m_engine_servername
			);
		}
		m_client_init = true;
		Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info("client has started.");

		return bRes;
	}

	/**
	 * finalize Component server and Engine client.
	 * @param N/A
	 * @return N/A
	 */
	public void finalize()
	{
		//-----------------------------------------------
		// disconnect from the engine
		//-----------------------------------------------
		if(m_engine_init)
		{
			if(disconnect())
			{
				m_engine_init = false;
			}
		}

		//-----------------------------------------------
		// stop the client
		//-----------------------------------------------
		if(m_client_init)
		{
			m_Engines.client_p.stop(m_engine_servername);
			m_client_init = false;
			Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info("client has stopped.");
		}

		//-----------------------------------------------
		// stop the server
		//-----------------------------------------------
		if(m_server_init)
		{
			m_server_op_impl.stop();
			m_server_init = false;
			Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info("server has stopped.");
		}
	}

////////////////////////////////////////////////////////////////////////////////////////////////////
// For Engine Interface
////////////////////////////////////////////////////////////////////////////////////////////////////
	/**
	 * request connection to Engine.
	 * @param N/A
	 * @return true/false
	 */
	public boolean connect()
	{
		boolean bRes = false;
		if(m_Engines.client_p.m_eng_ref!=null)
		{
			bRes = m_Engines.client_p.m_eng_ref.connect(
				m_component_nameservice,
				m_component_servername
			);
		}
		if(bRes)
		{
			m_engine_init = true;
		}
		return bRes;
	}

	/**
	 * request disconnection from Engine.
	 * @param N/A
	 * @return true/false
	 */
	public boolean disconnect()
	{
		boolean bRes = false;
		if(m_Engines.client_p.m_eng_ref!=null)
		{
			bRes = m_Engines.client_p.m_eng_ref.disconnect(
				m_component_servername
			);
		}
		if(bRes)
		{
			m_engine_init = false;
		}
		return bRes;
	}

	/**
	 * send "completed" message for a requested command message.
	 * @param command_id ID of the received command message
	 * @param status status of the command completion
	 * @param results result parameter(s) of the command execution
	 */
	public void completed(
		String command_id,
		Completed_Status status,
		ResultListHolder results
	)
	{
		//@@ FOR DUMMY: send to only 1 server that is specified in INI file (tentatively)
		// save result
		setCommandResult(
			m_engine_servername,
			command_id,
			status,
			results
		);
		// send message
		if(m_Engines.client_p.m_eng_ref!=null)
		{
			m_Engines.client_p.m_eng_ref.completed(
				m_component_servername,
				command_id,
				status
			);
		}
	}

	/**
	 * send "receive_event" message for a subscribed event.
	 * @param event_type type of the subscribed event
	 * @param subscribe_id ID of the subscribed event
	 * @param results result parameter(s) of the event
	 */
	public void receive_event(
		String event_type,
		String subscribe_id,
		ResultListHolder results
	)
	{
		//@@ FOR DUMMY: send to only 1 server that is specified in INI file (tentatively)
		// save result
		StringBuffer event_id = new StringBuffer("");
		setEventDetail(
			m_engine_servername,
			event_type,
			subscribe_id,
			results,
			event_id
		);

		// send message
		if(m_Engines.client_p.m_eng_ref!=null)
		{
			m_Engines.client_p.m_eng_ref.receive_event(
				m_component_servername,
				event_id.toString(),
				event_type,
				subscribe_id
			);
		}
	}

	/**
	 * send "receive_error" message.
	 * @param error_type type of the error
	 * @param results result parameter(s) of the error
	 */
	public void receive_error(
		ErrorType error_type,
		ResultListHolder results
	)
	{
		//@@ FOR DUMMY: send to only 1 server that is specified in INI file (tentatively)
		// save results
		StringBuffer _error_id = new StringBuffer("");
		setErrorDetail(
			m_engine_servername,
			error_type,
			results,
			_error_id
		);
		// send message
		if(m_Engines.client_p.m_eng_ref!=null)
		{
			m_Engines.client_p.m_eng_ref.receive_error(
				m_component_servername,
				_error_id.toString(),
				error_type
			);
		}
	}

////////////////////////////////////////////////////////////////////////////////////////////////////
// For Access Internal Data
////////////////////////////////////////////////////////////////////////////////////////////////////
	/**
	 * get component server name defined in RoIS_COMPONENT_PARAM.properties.
	 * @param N/A
	 * @return CORBA server name
	 */
	public String getComponentServerName()
	{
		String strRes = "";
		strRes = this.m_component_servername;
		return strRes;
	}

	/**
	 * get current directory path.
	 * @return path
	 */
	public String getCurrentDirectory()
	{
		String strRes = "";
		strRes =this.m_current_directory;
		return strRes;
	}

	/**
	 * get profile file name of this component.
	 * @return xml file name
	 */
	public String getComponentProfileName()
	{
		String strRes = "";
		strRes = this.m_profile_filename;
		return strRes;
	}

	/**
	 * get initialization status.
	 * @return true/false
	 */
	public boolean isInitialize()
	{
		boolean bRes = false;
		if(m_server_init==true && m_client_init==true)
		{
			bRes = true;
		}
		return bRes;
	}

	/**
	 * get a list of connecting Engines.
	 * @param servername_list (out) list of server names
	 * @param nameservice_list (out) list of CORBA naming service names
	 * @return number of connecting engines
	 */
	public int getConnectingEngineList(
		Vector<String> servername_list,
		Vector<String> nameservice_list
	)
	{
		int iRes = 0;
		servername_list.clear();
		nameservice_list.clear();
		iRes = m_Engines.size;
		for(int i=0; i<iRes; i++)
		{
			servername_list.add(m_Engines.servername.get(i));
			nameservice_list.add(m_Engines.nameservice.get(i));
		}
		return iRes;
	}

	/**
	 * get index of the Engine in the connecting Engine list.
	 * @param servername Engine server name
	 * @return index
	 */
	public int getEngineIndexByServername(
		String servername
	)
	{
		int iRes = 0;
		iRes = m_Engines.getIndexByServername(servername);
		return iRes;
	}

	/**
	 * get a list of binding Engines.
	 * @param servername_list (out) list of server names
	 * @param commandTypes_list (out) list of requested command types
	 * @param commandIds_list (out) list of requested command IDs
	 * @return number of binding Engines
	 */
	public int getBindingEngineList(	//@@ 2011.08.27 Miki: add in JAVA version
		Vector<String> servername_list,
		Vector<Vector<String>> commandTypes_list,
		Vector<Vector<String>> commandIds_list
	)
	{
		int iRes = 0;
		int connect_size = m_Engines.size;
		for(int i=0; i<connect_size; i++)
		{
			int binding_engine_size = m_Engines.requested_commands.get(i).size;
			if(binding_engine_size>0)
			{
				servername_list.add(m_Engines.servername.get(i));
				int request_count = m_Engines.requested_commands.get(i).messages.get(0).id.size();
				Vector<String> types = new Vector<String>();
				Vector<String> ids = new Vector<String>();
				for(int j=0; j<request_count; j++)
				{
					types.add(m_Engines.requested_commands.get(i).messages.get(0).type.get(j));
					ids.add(m_Engines.requested_commands.get(i).messages.get(0).id.get(j));
				}
				commandTypes_list.add(types);
				commandIds_list.add(ids);
				iRes++;
			}
		}
		return iRes;
	}

	/**
	 * get number of binds by the engine.
	 * @param engine_index index of the engine
	 * @return number of binds
	 */
	public int getBindingEngineSize(
		int engine_index
	)
	{
		int iRes = 0;
		if(engine_index > m_Engines.size)
		{
			return iRes;
		}
		iRes = m_Engines.bind_size.get(engine_index);
		return iRes;
	}

	/**
	 * get number of requests by the engine.
	 * @param engine_index index of the engine
	 * @return number of Engines
	 */
	public int getRequestedCommandSize(
		int engine_index
	)
	{
		int iRes = 0;
		if(engine_index > m_Engines.size)
		{
			return iRes;
		}
		iRes = m_Engines.requested_commands.get(engine_index).size;
		return iRes;
	}

	/**
	 * get a list of sent "completed" messages.
	 * @param engine_index index of the Engine
	 * @param type (out) list of command types
	 * @param id (out) list of command IDs
	 * @param status (out) list of command completion status
	 * @return number of messages
	 */
	public int getSentCompletedMessages(
		int engine_index,
		Vector<String> type,
		Vector<String> id,
		Vector<String> status
	)
	{
		int iRes = 0;
		type.clear();
		id.clear();
		status.clear();
		if(engine_index > m_Engines.size)
		{
			return iRes;
		}
		iRes = m_Engines.requested_commands.get(engine_index).messages.get(0).size;
		for(int i=0; i<iRes; i++)
		{
			type.add(m_Engines.requested_commands.get(engine_index).messages.get(0).type.get(i));
			id.add(m_Engines.requested_commands.get(engine_index).messages.get(0).id.get(i));
			status.add(m_Engines.requested_commands.get(engine_index).messages.get(0).status.get(i));
		}
		return iRes;
	}

	/**
	 * get a list of subscribing Engines.
	 * @param servername_list (out) list of server names
	 * @param subscribeTypes_list (out) list of event types
	 * @param subscribeIds_list (out) list of subscribe IDs
	 * @return number of Engines
	 */
	public int getSubscribingEngineList(	//@@ 2011.08.27 Miki: add in JAVA test
		Vector<String> servername_list,
		Vector<Vector<String>> subscribeTypes_list,
		Vector<Vector<String>> subscribeIds_list
	)
	{
		int iRes = 0;
		int connect_size = m_Engines.size;
		for(int i=0; i<connect_size; i++)
		{
			int subscribing_engine_size = m_Engines.subscribed_events.get(i).size;
			if(subscribing_engine_size>0)
			{
				servername_list.add(m_Engines.servername.get(i));
				int subscribe_count = m_Engines.subscribed_events.get(i).referenceid.size();
				Vector<String> types = new Vector<String>();
				Vector<String> ids = new Vector<String>();
				for(int j=0; j<subscribe_count; j++)
				{
					types.add(m_Engines.subscribed_events.get(i).type.get(j));
					ids.add(m_Engines.subscribed_events.get(i).referenceid.get(j));
				}
				subscribeTypes_list.add(types);
				subscribeIds_list.add(ids);
				iRes++;
			}
		}
		return iRes;
	}

	/**
	 * get number of subscribed events by the Engine.
	 * @param engine_index index of the engine
	 * @return number of subscribed events
	 */
	public int getSubscribedEventSize(
		int engine_index
	)
	{
		int iRes = 0;
		if(engine_index > m_Engines.size)
		{
			return iRes;
		}
		iRes = m_Engines.subscribed_events.get(engine_index).size;
		return iRes;
	}

	/**
	 * get a list of sent "receive_event" messages.
	 * @param engine_index index of the engine
	 * @param event_index index of the event
	 * @param type (out) list of event types
	 * @param subscribe_id (out) list of subscribe IDs
	 * @param event_id (out) list of event IDs
	 * @return number of messages
	 */
	public int getSentEventMessages(
		int engine_index,
		int event_index,
		Vector<String> type,
		Vector<String> subscribe_id,
		Vector<String> event_id
	)
	{
		int iRes = 0;
		type.clear();
		subscribe_id.clear();
		event_id.clear();
		if(engine_index > m_Engines.size)
		{
			return iRes;
		}
		if(m_Engines.subscribed_events.get(engine_index).size==0)
		{
			return iRes;
		}
		iRes = m_Engines.subscribed_events.get(engine_index).messages.get(event_index).size;
		for(int i=0; i<iRes; i++)
		{
			type.add(m_Engines.subscribed_events.get(engine_index).type.get(event_index));
			subscribe_id.add(m_Engines.subscribed_events.get(engine_index).referenceid.get(event_index));
			event_id.add(m_Engines.subscribed_events.get(engine_index).messages.get(event_index).id.get(i));
		}
		if(iRes==0)
		{
			type.add(m_Engines.subscribed_events.get(engine_index).type.get(event_index));
			subscribe_id.add(m_Engines.subscribed_events.get(engine_index).referenceid.get(event_index));
			event_id.add("");
		}
		return iRes;
	}

	/**
	 * get a number of sent "receive_error" messages.
	 * @param type (out) list of error types
	 * @param id (out) list of error IDs
	 * @return number of messages
	 */
	public int getSentErrorMessages(
		Vector<String> type,
		Vector<String> id
	)
	{
		int iRes = 0;
		type.clear();
		id.clear();
		iRes = m_Engines.sent_errors.size;
		for(int i=0; i<iRes; i++)
		{
			type.add(m_Engines.sent_errors.type.get(i));
			id.add(m_Engines.sent_errors.id.get(i));
		}
		return iRes;
	}

	/**
	 * get result parameter(s) of a command completion.
	 * @param command_id ID of the command message
	 * @param results (out) result parameter(s)
	 * @return true/false
	 */
	public boolean getCommandResult(
		String command_id,
		ResultListHolder results
	)
	{
		boolean bRes = false;
		// check connection
		int server_size = m_Engines.size;
		if(server_size==0)
		{
			return bRes;
		}
		// check command_id
		int msg_index = -1;
		int param_size = 0;
		Vector<String> strName = new Vector<String>();
		Vector<String> strType = new Vector<String>();
		Vector<String> strValue = new Vector<String>();
		strName.clear();
		strType.clear();
		strValue.clear();
		for(int i=0; i<server_size; i++)
		{
			msg_index = m_Engines.requested_commands.get(i).messages.get(0).getIndexById(command_id);
			if(msg_index!=-1)
			{
				// read results
				param_size = m_Engines.requested_commands.get(i).messages.get(0).parameters.get(msg_index).size;
				for(int j=0; j<param_size; j++)
				{
					strName.add(m_Engines.requested_commands.get(i).messages.get(0).parameters.get(msg_index).name.get(j));
					strType.add(m_Engines.requested_commands.get(i).messages.get(0).parameters.get(msg_index).datatype.get(j));
					strValue.add(m_Engines.requested_commands.get(i).messages.get(0).parameters.get(msg_index).value.get(j));
				}
				bRes = true;
				break;
			}
		}
		//@@ typecast for RoIS
		Result[] _results = new Result[param_size];
		for(int i=0; i<param_size; i++)
		{
			_results[i] = new Result();
			_results[i].name = strName.get(i);
			_results[i].data_type_ref = strType.get(i);
			org.omg.CORBA.Any any_tmp = org.omg.CORBA.ORB.init().create_any();
			any_tmp.insert_string(strValue.get(i));
			_results[i].value = any_tmp;
		}
		results.value = _results;
		bRes = true;
		return bRes;
	}

	/**
	 * get result parameter(s) of a event message.
	 * @param event_id ID of the event message
	 * @param results (out) result parameter(s)
	 * @return true/false
	 */
	public boolean getEventDetail(
		String event_id,
		ResultListHolder results
	)
	{
		boolean bRes = false;
		// check connection
		int server_size = m_Engines.size;
		if(server_size==0)
		{
			return bRes;
		}
		// check event id
		int result_size = results.value.length;
		int event_size = 0;
		int msg_index = -1;
		int param_size = 0;

		for(int i=0; i<server_size; i++)
		{
			event_size = m_Engines.subscribed_events.get(i).size;
			for(int j=0; j<event_size; j++)
			{
				msg_index = m_Engines.subscribed_events.get(i).messages.get(j).getIndexById(event_id);
				if(msg_index!=-1)
				{
					// read results
					param_size = m_Engines.subscribed_events.get(i).messages.get(j).parameters.get(msg_index).size;
					// Return specified parameters when there are specified parameters
					if(result_size!=0)
					{
						for(int k=0; k<param_size; k++)
						{
							for(int l=0; l<result_size; l++)
							{
								String required_name = results.value[l].name;
								String required_datatype = results.value[l].data_type_ref;
								String saved_name = m_Engines.subscribed_events.get(i).messages.get(j).parameters.get(msg_index).name.get(k);
								String saved_type = m_Engines.subscribed_events.get(i).messages.get(j).parameters.get(msg_index).datatype.get(k);
								if(required_name.matches(saved_name) && required_datatype.matches(saved_type))
								{
									org.omg.CORBA.Any any_tmp = org.omg.CORBA.ORB.init().create_any();
									any_tmp.insert_string(
										m_Engines.subscribed_events.get(i).messages.get(j).parameters.get(msg_index).value.get(k)
									);
									results.value[l].value = any_tmp;
									bRes = true;
									break;
								}
							}
						}
					}
					// Return all parameters when there is no specified parameter
					else
					{
						Result[] _result = new Result[param_size];
						for(int k=0; k<param_size; k++)
						{
							_result[k] = new Result();
							_result[k].name = m_Engines.subscribed_events.get(i).messages.get(j).parameters.get(msg_index).name.get(k);
							_result[k].data_type_ref = m_Engines.subscribed_events.get(i).messages.get(j).parameters.get(msg_index).datatype.get(k);
							org.omg.CORBA.Any any_tmp = org.omg.CORBA.ORB.init().create_any();
							any_tmp.insert_string(
								m_Engines.subscribed_events.get(i).messages.get(j).parameters.get(msg_index).value.get(k)
							);
							_result[k].value = any_tmp;
						}
						results.value = _result;
						bRes = true;
					}
				}
			}
		}
		return bRes;
	}

	/**
	 * get result parameter(s) of a error message.
	 * @param error_id ID of the error message
	 * @param results (out) result parameter(s)
	 * @return true/false
	 */
	public boolean getErrorDetail(
		String error_id,
		ResultListHolder results
	)
	{
		boolean bRes = false;
		// check error message
		int msg_index = m_Engines.sent_errors.getIndexById(error_id);
		if(msg_index==-1)
		{
			return bRes;
		}
		// read results
		Vector<String> strName = new Vector<String>();
		Vector<String> strType = new Vector<String>();
		Vector<String> strValue = new Vector<String>();
		strName.clear();
		strType.clear();
		strValue.clear();
		int param_size = m_Engines.sent_errors.parameters.get(msg_index).size;
		for(int i=0; i<param_size; i++)
		{
			strName.add(m_Engines.sent_errors.parameters.get(msg_index).name.get(i));
			strType.add(m_Engines.sent_errors.parameters.get(msg_index).datatype.get(i));
			strValue.add(m_Engines.sent_errors.parameters.get(msg_index).value.get(i));
		}
		//@@ typecast for RoIS
		Result[] _results = new Result[param_size];
		for(int i=0; i<param_size; i++)
		{
			_results[i] = new Result();
			_results[i].name = strName.get(i);
			_results[i].data_type_ref = strType.get(i);
			org.omg.CORBA.Any any_tmp = org.omg.CORBA.ORB.init().create_any();
			any_tmp.insert_string(strValue.get(i));
			_results[i].value = any_tmp;
		}
		results.value = _results;
		bRes = true;
		return bRes;
	}

////////////////////////////////////////////////////////////////////////////////////////////////////
// For Access Internal Data (internal use only)
////////////////////////////////////////////////////////////////////////////////////////////////////
	/**
	 * (INTERNAL USE ONLY) save a Engine server name and create a information holder object for the Engine.
	 * @param servername server name of the Engine
	 * @return true/false
	 */
	public boolean saveEngineName(
		String servername
	)
	{
		boolean bRes = false;
		if(servername!="")
		{
			int server_index = m_Engines.getIndexByServername(servername);
			if(server_index!=-1)
			{
				if(m_Engines.bind_size.get(server_index) < m_component_bindmax)
				{
					m_Engines.requested_commands.get(server_index).push_back(
						"",
						servername
					);
					int itmp = m_Engines.bind_size.get(server_index) + 1;
					m_Engines.bind_size.set(server_index, itmp);
					bRes = true;
					return bRes;
				}
			}
		}
		return bRes;
	}

	/**
	 * (INTERNAL USE ONLY) erase a engine server and delete a information holder object of the Engine.
	 * @param servername server name of the Engine
	 * @return true/false
	 */
	public boolean eraseEngineName(
		String servername
	)
	{
		boolean bRes = false;
		if(servername!="")
		{
			int server_index = m_Engines.getIndexByServername(servername);
			if(server_index!=-1)
			{
				if(m_Engines.bind_size.get(server_index)!=0)
				{
					m_Engines.requested_commands.get(server_index).eraseByReferenceID(servername);
					int itmp = m_Engines.bind_size.get(server_index) - 1;
					m_Engines.bind_size.set(server_index, itmp);
					bRes = true;
					return bRes;
				}
			}
		}
		return bRes;
	}

	/**
	 * (INTERNAL USE ONLY) create a new command message ID for a Engine and save information of the command message in the information holder object.
	 * @param servername server name of the Engine
	 * @param command_type type of the command message
	 * @return new command message ID
	 */
	public String createCommandMessageID(
		String servername,
		String command_type
	)
	{
		String strRes = "";
		int server_index = m_Engines.getIndexByServername(servername);
		if(server_index!=-1)
		{
			strRes = m_Engines.requested_commands.get(server_index).createMessageID();
			m_Engines.requested_commands.get(server_index).messages.get(0).push_back(
				command_type,
				strRes
			);
		}
		return strRes;
	}

	/**
	 * (INTERNAL USE ONLY) create a new event subscribe ID for a Engine and save information of the event message in the information holder object.
	 * @param servername server name of the Engine
	 * @param event_type type of the event message
	 * @return new event subscribe ID
	 */
	public String createEventSubscribeID(
		String servername,
		String event_type
	)
	{
		String strRes = "";
		int server_index = m_Engines.getIndexByServername(servername);
		if(server_index!=-1)
		{
			strRes = m_Engines.subscribed_events.get(server_index).createReferenceID();
			m_Engines.subscribed_events.get(server_index).push_back(
				event_type,
				strRes
			);
		}
		return strRes;
	}

	/**
	 * (INTERNAL USE ONLY) erase a subscribed event and delete information of the event message in the information holder object.
	 * @param servername server name of the Engine
	 * @param subscribe_id subcribe ID
	 * @return true/false
	 */
	public boolean eraseEventSubscribeID(
		String servername,
		String subscribe_id
	)
	{
		boolean bRes = false;
		int server_index = m_Engines.getIndexByServername(servername);
		if(server_index!=-1)
		{
			m_Engines.subscribed_events.get(server_index).eraseByReferenceID(subscribe_id);
			bRes = true;
		}
		return bRes;
	}

	/**
	 * save result parameter(s) of a error message.
	 * @param servername server name of the Engine
	 * @param error_type type of the error message
	 * @param results result parameter(s) of the error
	 * @param error_id ID of the error
	 * @return true/false
	 */
	private boolean setErrorDetail(
		String servername,
		ErrorType error_type,
		ResultListHolder results,
		StringBuffer error_id
	)
	{
		boolean bRes = false;
		// check connection
		int server_index = m_Engines.getIndexByServername(servername);
		if(server_index==-1)
		{
			return bRes;
		}
		// check error type
		String strErrType;
		switch(error_type.value())
		{
			case ErrorType._ENGINE_INTERNAL_ERROR:
				strErrType = "ENGINE_INTERNAL_ERROR";
				break;
			case ErrorType._COMPONENT_INTERNAL_ERROR:
				strErrType = "COMPONENT_INTERNAL_ERROR";
				break;
			case ErrorType._COMPONENT_NOT_RESPONDING:
				strErrType = "COMPONENT_NOT_RESPONDING";
				break;
			case ErrorType._USER_DEFINED_ERROR:
				strErrType = "USER_DEFINED_ERROR";
				break;
			default:
				strErrType = "NOT_DEFINED";
				break;
		}
		// create event id
		String _error_id = m_Engines.createErrorID();
		error_id.append(_error_id);
		// save message
		m_Engines.sent_errors.push_back(
			strErrType,
			_error_id
		);
		// save results
		int param_size = results.value.length;
		for(int i=0; i<param_size; i++)
		{
			//@@ FOR DUMMY: treat "any" as "string" (tentatively)
			int msg_index = m_Engines.sent_errors.getIndexById(_error_id);
			m_Engines.sent_errors.parameters.get(msg_index).push_back(
				results.value[i].name,
				results.value[i].data_type_ref,
				results.value[i].value.extract_string()
			);
		}
		bRes = true;
		return bRes;
	}

	/**
	 * save result parameter(s) of a command message.
	 * @param servername server name of the Engine
	 * @param command_id ID of the command
	 * @param status status of the command completion
	 * @param results result parameter(s) of the command
	 * @return true/false
	 */
	private boolean setCommandResult(
		String servername,
		String command_id,
		Completed_Status status,
		ResultListHolder results
	)
	{
		boolean bRes = false;
		// check connection
		int server_index = m_Engines.getIndexByServername(servername);
		if(server_index==-1)
		{
			return bRes;
		}
		int msg_size = m_Engines.requested_commands.get(server_index).size;
		if(msg_size==0)
		{
			Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).info("no requested command.");
			return bRes;
		}
		int msg_index = m_Engines.requested_commands.get(server_index).messages.get(0).getIndexById(command_id);
		if(msg_index==-1)
		{
			return bRes;
		}
		// save status
		String strStatus;
		switch(status.value())
		{
			case Completed_Status._CMD_OK:
				strStatus = "CMD_OK";
				break;
			case Completed_Status._CMD_ERROR:
				strStatus = "CMD_ERROR";
				break;
			case Completed_Status._CMD_ABORT:
				strStatus = "CMD_ABORT";
				break;
			case Completed_Status._CMD_OUT_OF_RESOURCES:
				strStatus = "CMD_OUT";
				break;
			case Completed_Status._CMD_TIMEOUT:
				strStatus = "CMD_TIMEOUT";
				break;
			default:
				strStatus = "NOT_DEFINED";
				break;
		}
		m_Engines.requested_commands.get(server_index).messages.get(0).status.set(msg_index, strStatus);
		// save results
		int param_size = results.value.length;
		for(int i=0; i<param_size; i++)
		{
			//@@ FOR DUMMY: treat "any" as "string" (tentatively)
			m_Engines.requested_commands.get(server_index).messages.get(0).parameters.get(msg_index).push_back(
				results.value[i].name,
				results.value[i].data_type_ref,
				results.value[i].value.extract_string()
			);
		}
		bRes = true;
		return bRes;
	}

	/**
	 * save result parameter(s) of a event message.
	 * @param servername server name of the Engine
	 * @param event_type type of the event
	 * @param subscribe_id subscribe ID of the event
	 * @param results result parameter(s) if the event
	 * @param event_id event ID of the event message
	 * @return true/false
	 */
	private boolean setEventDetail(
		String servername,
		String event_type,
		String subscribe_id,
		ResultListHolder results,
		StringBuffer event_id
	)
	{
		boolean bRes = false;
		// check connection
		int server_index = m_Engines.getIndexByServername(servername);
		if(server_index==-1)
		{
			return bRes;
		}
		// check subscribe id
		int event_index = m_Engines.subscribed_events.get(server_index).getIndexByReferenceId(subscribe_id);
		if(event_index==-1)
		{
			return bRes;
		}
		// check event type
		if(!m_Engines.subscribed_events.get(server_index).type.get(event_index).matches(event_type))
		{
			return bRes;
		}
		// create event id
		String _event_id = m_Engines.subscribed_events.get(server_index).createMessageID();
		event_id.append(_event_id);
		// save message
		m_Engines.subscribed_events.get(server_index).messages.get(event_index).push_back(
			event_type,
			_event_id
		);
		int msg_index = m_Engines.subscribed_events.get(server_index).messages.get(event_index).getIndexById(_event_id);
		// save results
		int param_size = results.value.length;
		for(int i=0; i<param_size; i++)
		{
			//@@ FOR DUMMY: treat "any" as "string" (tentatively)
			m_Engines.subscribed_events.get(server_index).messages.get(event_index).parameters.get(msg_index).push_back(
				results.value[i].name,
				results.value[i].data_type_ref,
				results.value[i].value.extract_string()
			);
		}
		bRes = true;
		return bRes;
	}
}
